#include "Window.h"
#include <Windows.h>

namespace Caelum {

LRESULT CALLBACK StdWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

void Window::Initialize(WindowParams &wp)
{
	mWindowParams = wp;

	WNDCLASS wc;
	ZeroMemory(&wc, sizeof(wc));
	wc.hInstance = GetModuleHandle(NULL);
	wc.lpszClassName = TEXT("CaelumMainWindow");
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.lpfnWndProc = (WNDPROC)StdWindowProc;
	
	if (wp.IsGameWindow)
		wc.hbrBackground = NULL;
	else
		wc.hbrBackground = (HBRUSH)COLOR_WINDOW;

	RegisterClass(&wc);

	DWORD style = WS_OVERLAPPEDWINDOW;

	if (wp.Title.length() == 0)
		wp.Title = L"Caelum";

	mWindowPtr = (unsigned long)CreateWindow(
		TEXT("CaelumMainWindow"),
		wp.Title.c_str(),
		style,
		wp.X, wp.Y, wp.Width, wp.Height,
		NULL, NULL, GetModuleHandle(NULL), NULL);

	SetWindowLongPtr((HWND)mWindowPtr, GWL_USERDATA, (LONG_PTR)this);
}

void Window::Show()
{
	ShowWindow((HWND)mWindowPtr, SW_NORMAL);
}

void Window::Hide()
{
	ShowWindow((HWND)mWindowPtr, SW_HIDE);
}

void Window::MoveTo(uint X, uint Y)
{
	uint W = 0, H = 0;
	this->GetTotalSize(W, H);
	MoveWindow((HWND)mWindowPtr, X, Y, W, H, true);
}

void Window::Resize(uint Width, uint Height)
{
	uint X = 0, Y = 0;
	this->GetPosition(X, Y);
	MoveWindow((HWND)mWindowPtr, X, Y, Width, Height, true);
}

void Window::GetPosition(uint &X, uint &Y)
{
	RECT rc;
	GetWindowRect((HWND)mWindowPtr, &rc);
	X = rc.left;
	Y = rc.top;
}

void Window::GetTotalSize(uint &Width, uint &Height)
{
	RECT rc;
	GetWindowRect((HWND)mWindowPtr, &rc);
	Width = rc.right;
	Height = rc.bottom;
}

void Window::GetClientSize(uint &Width, uint &Height)
{
	RECT rc;
	GetClientRect((HWND)mWindowPtr, &rc);
	Width = rc.right;
	Height = rc.bottom;
}

bool Window::ProcessMessages()
{
	MSG msg;
	while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
	{
		if (msg.message == WM_QUIT)
			return false;
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return true;
}

LRESULT CALLBACK StdWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_DESTROY:
	case WM_CLOSE:
		{
			PostQuitMessage(0);
			break;
		}
	case WM_SIZE:
		{
			Window *wnd = (Window*)GetWindowLongPtr(hWnd, GWL_USERDATA);
			wnd->Resizing(LOWORD(lParam), HIWORD(lParam));
			break;
		}
	}
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

int WindowParams::OSDefaultPos = CW_USEDEFAULT;
WindowParams WindowParams::BasicGameWindow = { WindowParams::OSDefaultPos, WindowParams::OSDefaultPos, 800, 600, L"Caelum", false, true };

}